package com.study.d018tasks;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.concurrent.Worker.State;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

/**多任务Task类的使用
*@description
*@author xtayhame
*date 2020年3月16日
*version
*since v1.0
*/
public class TaskMain extends Application{
	public static void main(String[] args) {
		launch(args);
	}

	@Override
	public void start(Stage stage) throws Exception {
		AnchorPane anchorPane = new AnchorPane();

		Button startButton = new Button("开始");
		Button cancelButton = new Button("取消");

		ProgressBar  progressBar = new ProgressBar(0.0);
		Label statLabel = new Label("stat");
		Label valueLabel = new Label("value");
		Label titleLable = new Label("title");
		Label messageLable = new Label("message");


		HBox hBox = new HBox(15);
		hBox.getChildren().addAll(startButton,cancelButton, progressBar,statLabel,valueLabel,titleLable,messageLable);

		AnchorPane.setTopAnchor(hBox, 30.0);
		AnchorPane.setLeftAnchor(hBox, 30.0);

		anchorPane.getChildren().add(hBox);
		stage.setScene(new Scene(anchorPane, 500, 400));
		stage.show();


		MyTask task = new MyTask();
		Thread thread = new Thread(task);
		//设置为守护线程， 如果不设置，则窗口关闭后，线程仍在运行
		thread.setDaemon(true);

		//开始线程
		startButton.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent event) {
				thread.start();
			}
		});

		cancelButton.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent event) {
				thread.stop();
			}
		});

		//监听进度
		task.progressProperty().addListener(new ChangeListener<Number>() {
			@Override
			public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
				//valueLabel.setText(newValue.toString());
				//注意：这里绝对不能使用intValue()进行转换 ,如果转换为int类，则滚动条的进度无法显示，这里需要的是double类型的参数
				progressBar.setProgress(newValue.doubleValue());
			}
		});

		//监听值
		task.valueProperty().addListener(new ChangeListener<Number>() {
			@Override
			public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
				valueLabel.setText(newValue.toString());
			}
		});

		//监听状态
		task.stateProperty().addListener(new ChangeListener<State>() {
			@Override
			public void changed(ObservableValue<? extends State> observable, State oldValue, State newValue) {
				statLabel.setText("当前状态：" +newValue.name());
				System.out.println("线程状态:" + newValue.name());
				/**
				 * State.SCHEDULED 准备
				 * State.RUNNING   运行
				 * State.SUCCEEDED 成功
				 */
			}
		});

		//监听消息
		task.messageProperty().addListener(new ChangeListener<String>() {
			@Override
			public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
				messageLable.setText(newValue);
				System.out.println("消息：" + newValue);
			}
		});

		//标题监听
		task.titleProperty().addListener(new ChangeListener<String>() {
			@Override
			public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
				titleLable.setText(newValue);
				System.out.println("标题：" + newValue);
			}
		});


		//捕获异常
		task.exceptionProperty().addListener(new ChangeListener<Throwable>() {

			@Override
			public void changed(ObservableValue<? extends Throwable> observable, Throwable oldValue,
					Throwable newValue) {
				System.out.println(newValue);
			}
		});


	}


}


class MyTask extends Task<Double>{
	//主要是实现call()方法
	@Override
	protected Double call() throws Exception {
		System.out.println("call() 中对应的线程：  是否是FX线程：" + Platform.isFxApplicationThread() + "     线程名称：" + Thread.currentThread().getName());

		this.updateTitle("复制");

		byte[] bytes= new byte[1024 * 4];
		FileInputStream input =null;
		FileOutputStream output =null;

		double total=0;   //记录文件总的大小

		double hasCopy=0; //已经复制的字节数

		double progress=0.0;  //当前进度值

		try {

			input = new FileInputStream(new File("H:\\MV\\test\\黄玫瑰.mp3"));
			output = new FileOutputStream(new File("H:\\MV\\test\\黄玫瑰2.mp3"));

			total = input.available();

			int i=0;
			while((i=input.read(bytes)) !=-1){
				if(isCancelled()){
					System.out.println("取消线程");
					break;
				}

				output.write(bytes, 0, i);
				//休眠5秒
				Thread.sleep(3);

				hasCopy = hasCopy + i;

				progress = hasCopy / total;
				//System.out.println("hasCopy="+hasCopy+" , total="+total+",   当前进度："+ progress);

				//改变title
				if(progress < 0.5){
					this.updateTitle("正在复制，请耐心等待.");
					this.updateMessage("【消息】正在复制");
				}else if(progress < 0.5){
					this.updateTitle("马上复制完毕.");
					this.updateMessage("【消息】马上复制完毕");
				}else{
					this.updateMessage("复制完毕.");
					this.updateMessage("【消息】复制完毕");
				}

				//注意：这两步的调用很关键

				//调用updateProgress()会 触发task.progressProperty()监听
				this.updateProgress(hasCopy, total);

				//调用updateValue()会 触发task.valueProperty()监听
				this.updateValue(progress);
			}
			output.flush();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			if(output !=null){
				output.close();
			}
		}

		//返回百分比
		System.out.println("progress="+ progress);
		return progress;
		//return 0.5;
	}

	/******************可选实现方法*******************/




	//call()执行完后的返回值，会返回到updateValue()方法中
	/*@Override
	protected void updateValue(Double value) {
		super.updateValue(value);
		System.out.println("updateValue 中对应的线程：  是否是FX线程：" + Platform.isFxApplicationThread() + "     线程名称：" + Thread.currentThread().getName());

		//updateValue 是UI线程，可以在这里更改UI操作

	}*/




}


